//---------------------------------------------------------------------------------
// Copyright (c) 2008 VoiceLynx Project
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
//     1. The origin of this software must not be misrepresented; you must not
//        claim that you wrote the original software. If you use this software
//        in a product, an acknowledgment in the product documentation would be
//        appreciated but is not required.
//
//     2. Altered source versions must be plainly marked as such, and must not be
//        misrepresented as being the original software.
//
//     3. This notice may not be removed or altered from any source
//        distribution.
//---------------------------------------------------------------------------------

// NOTE: Originally came from the metaphor game engine project. I created that project, and
// have it licensed under the same license, so I am omitting metaphor's license. This set of
// classes will probably need a rewrite for coding standards, efficiency, and security 
// reasons anyways

#ifndef __VLDataStream_h__
#define __VLDataStream_h__

#include "VLPrerequisites.h"


//! Contains utility classes to manage data

//! Defines generic interface to be used when persisting objects

/// This namespace contains OutDataStream and InDataStream
///
/// These classes should be treated as a stream - information may not be 
/// pulled random access. All string names of variables are for validity checking 
/// (possibly only enabled in debug mode.)
///
/// To save:
///
/// @code
///
/// OutDataStream dsOut;
/// dsOut.writeData("MyData", myData);
/// dsOut.writeData("MyData2", myData2);
/// dsOut.writeData("MyData3", myData3);
///
/// @endcode
///
/// To read:
///
/// @code
///
/// ds.readData("MyData", &myData); // <-- "MyData" must equal what was above
/// ds.readData("MyData2", &myData2); // <-- "MyData2" must equal what was above
/// ds.readData("MyData3", &myData3); // <-- "MyData3" must equal what was above
///
/// @endcode
///
/// As a general rule, if the functions are a pointer, it's an OUT param. If it's
/// a reference or pass-by-value, then it's an IN param


enum dataType{
  beginType,
  stringType,
  intType,
  floatType,
  byteArrayType,
  unsignedIntType,
  boolType,
  endType
};

//TODO: Some of the things in this class are not as secure as they
//could be. I don't think anything here could cause a buffer overflow,
//but there are a couple places where an attacker might cause the
//server to choke on a malformed packet.


class OutDataStream
{
private:
  VLByteArrayPtr mData;
  void insertObject(const void*object,int length);
public:
  OutDataStream();
  virtual ~OutDataStream();

  virtual void writeData(const std::string &name, int data);
  virtual void writeData(const std::string &name, unsigned int data);
  virtual void writeData(const std::string &name, bool data);
  virtual void writeData(const std::string &name, std::string &data);
  virtual void writeData(const std::string &name, float &data);
  virtual void writeData(const std::string &name, VLByteArray &data);

  byte *getBytePtr() { return ((mData->size() > 0) ? &(*mData.get())[0] : 0); }
  size_t getSize() { return mData->size(); }
  VLByteArrayPtr takeData();
};

class InDataStream
{
private:
  VLByteArrayPtr mData;
  void getObject(void *object, int length, bool advanceReadPointer = true);
  int mDataPtr;

public:
  InDataStream(VLByteArrayPtr bytes);
  virtual ~InDataStream();

  virtual void readData(const std::string &name, int *data);
  virtual void readData(const std::string &name, unsigned int *data);
  virtual void readData(const std::string &name, bool *data);
  virtual void readData(const std::string &name, std::string *data);
  virtual void readData(const std::string &name, float *data);
  virtual void readData(const std::string &name, VLByteArray &data);

  virtual void reset();
  virtual bool isEmpty();    
};


#endif